纸上得来终觉浅,绝知此事要躬行
前言
很久前看过webpack
,入职来一直做小程序快应用相关需求,对于框架和工程化的东西渐渐拉下了,忽然发现webpack都到4.0了,想想之前看还是2.0时代,真是是新月异啊,webpack
入门的初始化配置就不再记述,基本看下编译之后的文件就能读明白(普通模块依赖、动态引用编译)主要记述下自己看tree shaking
时的坑。
Tree Shaking
它是何方神圣
首先介绍下什么是tree shaking
,可以理解为通过工具”摇”我们的JS文件,将其中用不到的代码”摇”掉,是一个性能优化的范畴。具体来说,在 webpack
项目中,有一个入口文件,相当于一棵树的主干,入口文件有很多依赖的模块,相当于树枝。实际情况中,虽然依赖了某个模块,但其实只使用其中的某些功能。通过tree-shaking
,将没有使用的模块摇掉,这样来达到删除无用代码的目的。
how原理
Tree-shaking 较早由 Rich_Harris 的 rollup 实现,后来,webpack2
也增加了tree-shaking
的功能。
Tree-shaking
的本质是消除无用的js代码,这个称之为DCE(dead code elimination)
。
Dead Code
一般具有以下几个特征:
- 代码不会被执行,不可到达
- 代码执行的结果不会被用到
- 代码只会影响死变量(只写不读)
传统编译型的语言中,都是由编译器将Dead Code
从AST(抽象语法树)中删除,那javascript中是由谁做DCE呢?
首先肯定不是浏览器做DCE,因为当我们的代码送到浏览器,那还谈什么消除无法执行的代码来优化呢,所以肯定是送到浏览器之前的步骤进行优化。
其实也不是通常使用的打包工具rollup、webpack
做的,而是著名的代码压缩优化工具uglify,uglify完成了javascript的DCE(本人就是因为知道这一点纠结了很久,5555)。
看下编译代码
首先时入口和依赖文件,可以看到math.js导出了square和cube两个函数,index.js引入了其中一个,按照前面说的原理编译后不应该存在cube导出的函数的,结果却出乎预料。
1 | // index.js 入口文件 |
1 | // math.js |
编译后代码:
1 | /******/ (function(modules) { // webpackBootstrap |
其实主要就是最后那个eval函数,可以看到cube和square函数都有定义,当时花了很多时间调试,比如和babel编译冲突,等等,最后居然发现是开发模式的原因,巨坑啊,webpack文档上写的就是开发模式的,哎,到底还是对原理了解不深,前面也说了tree shaking的原理是使用uglify实现的。
想想也能理解,开发模式是不开启开启压缩的,接下来看下压缩后的编译代码:
1 | ! function(e) { |
主要关注最后的立即执行函数传入的参数数组即可,可以看到现在只有用到的cube函数了。
1 | ! function(e) { |